前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# koa2使用cookie

30 秒速记

  • Koa 自带 ctx.cookies,底层是 npm 的 cookies 模块,读请求头里的 Cookie、写响应头里的 Set-Cookie
  • 单个 Cookie 大约 4KB 上限,同域每个请求都会带上,只放 sessionId 这类标识
  • httpOnly(Koa 默认 true)防脚本读、secure 只走 HTTPS、sameSite 管跨站携带、path / domain 管作用范围
  • signed: true 要先配 app.keys,只防篡改不加密,内容照样明文可见
  • 删除 = 同名同 path / domain 再写一次空值让它过期,作用域对不上就删不掉

Cookie 说白了是服务端塞给浏览器的一张小纸条,浏览器之后每次请求同域都会自动带回来。 在 Koa 里写用 ctx.cookies.set(),读用 ctx.cookies.get()。因为每个请求都会带、容量又只有 4KB 左右,我只往里放 sessionId 这种标识,真正的用户数据放服务端。几个属性各管一摊:httpOnly 让 document.cookie 读不到,secure 让它只在 HTTPS 下发送,sameSite 限制第三方站点发请求时带不带它。签名只是防止用户改值,不是加密,敏感信息一样不能放。

理解「koa2使用cookie」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Cookie 的工作流程只有两步:服务端在响应里写 Set-Cookie,浏览器存下来;之后浏览器发请求时,凡是域名、路径、协议都匹配的 Cookie,自动拼进请求头 Cookie 里带回去。Koa 把这两步封装成了 ctx.cookies.set() 和 ctx.cookies.get(),底层是 pillarjs/cookies 这个包。

const Koa = require('koa')
const app = new Koa()
app.keys = [process.env.COOKIE_SECRET || 'dev-secret'] // 用 signed 必须配

app.use(async (ctx) => {
  if (ctx.path === '/login') {
    ctx.cookies.set('sid', 'abc123', {
      httpOnly: true,          // 默认就是 true,document.cookie 读不到
      sameSite: 'lax',         // 第三方站点发起的 POST 不带它
      maxAge: 30 * 60 * 1000,  // 毫秒,30 分钟
      signed: true             // 额外写一个 sid.sig 防篡改
    })
    ctx.body = 'logged in'
  } else {
    ctx.body = ctx.cookies.get('sid', { signed: true }) || 'no cookie'
  }
})
app.listen(3000)
// curl -i localhost:3000/login  -> 响应头里有两条 Set-Cookie:sid 和 sid.sig
@前端进阶之旅: 代码已经复制到剪贴板

记住三条就够用:只存标识不存数据;登录凭证一律 httpOnly,生产环境加 secure;删除时 path、domain 要和写入时完全一致。

面试官追问

追问 1Cookie 里存了 userId=123,用户自己改成 456 是不是就登录别人账号了?
参考回答

不签名的话就是。要么开 signed: true(配合 app.keys),改了值签名对不上,get 时带 { signed: true } 会读到 undefined;更好的做法是只存随机的 sessionId,用户信息放服务端。

追问 2前端想用 document.cookie 读登录态,却发现读不到 session,是出问题了吗?
参考回答

不是,Koa 的 ctx.cookies.set 默认就是 httpOnly: true,脚本读不到正是想要的效果。前端要知道登录没登录,调一个 /api/me 接口就行,别为这个把 httpOnly 关掉。

追问 3Cookie 和 localStorage 存 token,怎么选?
参考回答

localStorage 不会自动带上请求,要手动塞 Authorization 头,XSS 能直接读走;httpOnly 的 Cookie 脚本读不到,但会自动携带,要靠 sameSite 和 CSRF token 防跨站请求。同域的传统 Web 应用我倾向 httpOnly Cookie。

追问 4给 Cookie 加了 signed: true,服务启动就报错了,缺了什么?
参考回答

缺 app.keys。签名要用密钥算 HMAC,写成 app.keys = ['some-secret'],密钥走环境变量别写死。设置后响应里会多一个 name.sig 的 Cookie。

追问 5页面一个请求的请求头里带了 6KB 的 Cookie,会有什么问题?
参考回答

每个请求都白白多传这么多字节,静态资源请求也不放过;有的服务器或网关对请求头大小有限制,超了直接返回 400 / 431。把大数据挪到服务端,静态资源放到不带 Cookie 的独立域名。

# koa2使用cookie

# 使用方法

30 秒速记

  • 读:ctx.cookies.get(name, [options]),读的是这次请求带上来的 Cookie
  • 写:ctx.cookies.set(name, value, [options]),写进这次响应的 Set-Cookie
  • 同一个请求里先 set 再 get 拿不到新值,要等浏览器下一次请求带回来
  • 选项语义以底层 cookies 模块为准:maxAge 是毫秒、httpOnly 默认 true、overwrite 默认 false
  • 删除:ctx.cookies.set(name, null, sameScopeOptions)

Koa 在上下文上直接给了 ctx.cookies.get 和 ctx.cookies.set 两个方法,一个读请求、一个写响应。 这一点很多人会搞混:set 只是往响应头里加了一条 Set-Cookie,当前请求的 Cookie 头不会变,所以紧接着 get 是拿不到的。它底层用的是 pillarjs/cookies,选项怎么写、默认值是什么都去看那个包的文档。比如 maxAge 单位是毫秒,httpOnly 默认开着,这两个最容易写错。

koa提供了从上下文直接读取、写入cookie的方法

  • ctx.cookies.get(name, [options]) 读取上下文请求中的cookie
  • ctx.cookies.set(name, value, [options]) 在上下文中写入cookie

koa2 中操作的cookies是使用了npm的cookies模块,源码在 https://github.com/pillarjs/cookies,所以在读写cookie的使用参数与该模块的使用一致。

面试官追问

追问 1登录接口里 set 完 token,下一行 get('token') 是 undefined,为什么?
参考回答

get 读的是请求头,set 写的是响应头,两者不是同一份数据。同一个请求里要用这个值就直接用变量,别绕回 Cookie 读。

追问 2写了 maxAge: 3600,结果 Cookie 几秒就没了?
参考回答

ctx.cookies 的 maxAge 单位是毫秒,3600 就是 3.6 秒。一小时要写 3600 * 1000。

追问 3想删掉一个 Cookie,怎么写?
参考回答

ctx.cookies.set('token', null, { path: '/', domain: 'example.com' }),值传 null,模块会把过期时间设到 1970 年。path 和 domain 必须和写入时一样,否则删的是另一枚。

追问 4同事想绕开 ctx.cookies,自己拼 Set-Cookie 头,你同意吗?
参考回答

一般不同意。自己拼要处理编码、多条 Set-Cookie 合并、签名这些细节,很容易写出浏览器拒收的格式。ctx.cookies 不支持的属性才考虑手写,而且要集中在一个工具函数里。

追问 5签名 Cookie 读的时候拿到 undefined,但浏览器里明明有值,怎么回事?
参考回答

先看 get 有没有传 { signed: true },再看 app.keys 是不是换过。密钥轮换要把新密钥放数组第一位、旧的留在后面,cookies 会用旧密钥验签并自动重签,直接替换会让所有老 Cookie 失效。

# 例子代码

30 秒速记

  • 访问 /index 时写入 cid=hello world,其他路径只返回 hello world
  • domain: 'localhost' 意味着必须用 localhost 访问,用 127.0.0.1 打开浏览器会拒收
  • path: '/index' → 只有 /index 及其子路径的请求会带上它,全站用的要写 /
  • maxAge 和 expires 同时写时,cookies
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

koa2使用cookie|Nodejs专题系列

# koa2使用cookie

30 秒速记

  • Koa 自带 ctx.cookies,底层是 npm 的 cookies 模块,读请求头里的 Cookie、写响应头里的 Set-Cookie
  • 单个 Cookie 大约 4KB 上限,同域每个请求都会带上,只放 sessionId 这类标识
  • httpOnly(Koa 默认 true)防脚本读、secure 只走 HTTPS、sameSite 管跨站携带、path / domain 管作用范围
  • signed: true 要先配 app.keys,只防篡改不加密,内容照样明文可见
  • 删除 = 同名同 path / domain 再写一次空值让它过期,作用域对不上就删不掉

Cookie 说白了是服务端塞给浏览器的一张小纸条,浏览器之后每次请求同域都会自动带回来。 在 Koa 里写用 ctx.cookies.set(),读用 ctx.cookies.get()。因为每个请求都会带、容量又只有 4KB 左右,我只往里放 sessionId 这种标识,真正的用户数据放服务端。几个属性各管一摊:httpOnly 让 document.cookie 读不到,secure 让它只在 HTTPS 下发送,sameSite 限制第三方站点发请求时带不带它。签名只是防止用户改值,不是加密,敏感信息一样不能放。

理解「koa2使用cookie」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

Cookie 的工作流程只有两步:服务端在响应里写 Set-Cookie,浏览器存下来;之后浏览器发请求时,凡是域名、路径、协议都匹配的 Cookie,自动拼进请求头 Cookie 里带回去。Koa 把这两步封装成了 ctx.cookies.set() 和 ctx.cookies.get(),底层是 pillarjs/cookies 这个包。

const Koa = require('koa')
const app = new Koa()
app.keys = [process.env.COOKIE_SECRET || 'dev-secret'] // 用 signed 必须配

app.use(async (ctx) => {
  if (ctx.path === '/login') {
    ctx.cookies.set('sid', 'abc123', {
      httpOnly: true,          // 默认就是 true,document.cookie 读不到
      sameSite: 'lax',         // 第三方站点发起的 POST 不带它
      maxAge: 30 * 60 * 1000,  // 毫秒,30 分钟
      signed: true             // 额外写一个 sid.sig 防篡改
    })
    ctx.body = 'logged in'
  } else {
    ctx.body = ctx.cookies.get('sid', { signed: true }) || 'no cookie'
  }
})
app.listen(3000)
// curl -i localhost:3000/login  -> 响应头里有两条 Set-Cookie:sid 和 sid.sig
@前端进阶之旅: 代码已经复制到剪贴板

记住三条就够用:只存标识不存数据;登录凭证一律 httpOnly,生产环境加 secure;删除时 path、domain 要和写入时完全一致。

面试官追问

追问 1Cookie 里存了 userId=123,用户自己改成 456 是不是就登录别人账号了?
参考回答

不签名的话就是。要么开 signed: true(配合 app.keys),改了值签名对不上,get 时带 { signed: true } 会读到 undefined;更好的做法是只存随机的 sessionId,用户信息放服务端。

追问 2前端想用 document.cookie 读登录态,却发现读不到 session,是出问题了吗?
参考回答

不是,Koa 的 ctx.cookies.set 默认就是 httpOnly: true,脚本读不到正是想要的效果。前端要知道登录没登录,调一个 /api/me 接口就行,别为这个把 httpOnly 关掉。

追问 3Cookie 和 localStorage 存 token,怎么选?
参考回答

localStorage 不会自动带上请求,要手动塞 Authorization 头,XSS 能直接读走;httpOnly 的 Cookie 脚本读不到,但会自动携带,要靠 sameSite 和 CSRF token 防跨站请求。同域的传统 Web 应用我倾向 httpOnly Cookie。

追问 4给 Cookie 加了 signed: true,服务启动就报错了,缺了什么?
参考回答

缺 app.keys。签名要用密钥算 HMAC,写成 app.keys = ['some-secret'],密钥走环境变量别写死。设置后响应里会多一个 name.sig 的 Cookie。

追问 5页面一个请求的请求头里带了 6KB 的 Cookie,会有什么问题?
参考回答

每个请求都白白多传这么多字节,静态资源请求也不放过;有的服务器或网关对请求头大小有限制,超了直接返回 400 / 431。把大数据挪到服务端,静态资源放到不带 Cookie 的独立域名。

# koa2使用cookie

# 使用方法

30 秒速记

  • 读:ctx.cookies.get(name, [options]),读的是这次请求带上来的 Cookie
  • 写:ctx.cookies.set(name, value, [options]),写进这次响应的 Set-Cookie
  • 同一个请求里先 set 再 get 拿不到新值,要等浏览器下一次请求带回来
  • 选项语义以底层 cookies 模块为准:maxAge 是毫秒、httpOnly 默认 true、overwrite 默认 false
  • 删除:ctx.cookies.set(name, null, sameScopeOptions)

Koa 在上下文上直接给了 ctx.cookies.get 和 ctx.cookies.set 两个方法,一个读请求、一个写响应。 这一点很多人会搞混:set 只是往响应头里加了一条 Set-Cookie,当前请求的 Cookie 头不会变,所以紧接着 get 是拿不到的。它底层用的是 pillarjs/cookies,选项怎么写、默认值是什么都去看那个包的文档。比如 maxAge 单位是毫秒,httpOnly 默认开着,这两个最容易写错。

koa提供了从上下文直接读取、写入cookie的方法

  • ctx.cookies.get(name, [options]) 读取上下文请求中的cookie
  • ctx.cookies.set(name, value, [options]) 在上下文中写入cookie

koa2 中操作的cookies是使用了npm的cookies模块,源码在 https://github.com/pillarjs/cookies,所以在读写cookie的使用参数与该模块的使用一致。

面试官追问

追问 1登录接口里 set 完 token,下一行 get('token') 是 undefined,为什么?
参考回答

get 读的是请求头,set 写的是响应头,两者不是同一份数据。同一个请求里要用这个值就直接用变量,别绕回 Cookie 读。

追问 2写了 maxAge: 3600,结果 Cookie 几秒就没了?
参考回答

ctx.cookies 的 maxAge 单位是毫秒,3600 就是 3.6 秒。一小时要写 3600 * 1000。

追问 3想删掉一个 Cookie,怎么写?
参考回答

ctx.cookies.set('token', null, { path: '/', domain: 'example.com' }),值传 null,模块会把过期时间设到 1970 年。path 和 domain 必须和写入时一样,否则删的是另一枚。

追问 4同事想绕开 ctx.cookies,自己拼 Set-Cookie 头,你同意吗?
参考回答

一般不同意。自己拼要处理编码、多条 Set-Cookie 合并、签名这些细节,很容易写出浏览器拒收的格式。ctx.cookies 不支持的属性才考虑手写,而且要集中在一个工具函数里。

追问 5签名 Cookie 读的时候拿到 undefined,但浏览器里明明有值,怎么回事?
参考回答

先看 get 有没有传 { signed: true },再看 app.keys 是不是换过。密钥轮换要把新密钥放数组第一位、旧的留在后面,cookies 会用旧密钥验签并自动重签,直接替换会让所有老 Cookie 失效。

# 例子代码

30 秒速记

  • 访问 /index 时写入 cid=hello world,其他路径只返回 hello world
  • domain: 'localhost' 意味着必须用 localhost 访问,用 127.0.0.1 打开浏览器会拒收
  • path: '/index' → 只有 /index 及其子路径的请求会带上它,全站用的要写 /
  • maxAge 和 expires 同时写时,cookies 模块按 maxAge 重新算过期时间,expires 被覆盖
  • httpOnly: false 只是为了演示 document.cookie 能读到,登录凭证别这么写

这段代码就是在 /index 这个路由里调一次 ctx.cookies.set,把 cid 写给浏览器。 几个选项值得逐个看:domain 和 path 决定浏览器以后在哪些请求里带上它,这里限死在 localhost 的 /index 下;maxAge 是 10 分钟;expires 写了一个过去的日期,但 cookies 模块只要看到 maxAge 就会用当前时间加 maxAge 覆盖 expires,所以实际还是 10 分钟有效。两个过期选项我只写一个,免得读代码的人误判。httpOnly: false 是为了在控制台演示,真实项目里会话类的 Cookie 都保持默认的 true。

const Koa = require('koa')
const app = new Koa()

app.use( async ( ctx ) => {

  if ( ctx.url === '/index' ) {
    ctx.cookies.set(
      'cid',
      'hello world',
      {
        domain: 'localhost',  // 写cookie所在的域名
        path: '/index',       // 写cookie所在的路径
        maxAge: 10 * 60 * 1000, // cookie有效时长
        expires: new Date('2017-02-15'),  // cookie失效时间
        httpOnly: false,  // 是否只用于http请求中获取
        overwrite: false  // 是否允许重写
      }
    )
    ctx.body = 'cookie is ok'
  } else {
    ctx.body = 'hello world'
  }

})

app.listen(3000, () => {
  console.log('[demo] cookie is starting at port 3000')
})

@前端进阶之旅: 代码已经复制到剪贴板

← 4.2 koa static中间件5.2 koa2实现session →

fe